/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = http_core.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2015/02/27 by geyh                                 */
/*******************************************************************/


#include "frmem.h"
#include "frsutl.h"
#include "frlist.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "comm/http_basedata.h"
#include "comm/http_comm.h"
#include "http1/http_analysis.h"
#include "http2/nghttp2_parse.h"


#include "http_core.h"
#include "config.h"


#define FR_HTTP_LINE_END              "\r\n"
#define HTTP_HEADER_MAX_SIZE           1048576          /* 1M */

extern void *g_p_apm_context;

FR_STATIC int __http2_session_add(Frlist_header *p_lst_header, Http2_session **pp_session)
{
    Frlist_node *p_st_node = NULL;
    Http2_session *p_session = *pp_session;

    if(p_lst_header == NULL || pp_session == NULL)
        return FR_FAIL;

    p_st_node = frlist_node_create(p_session);
    if(p_st_node == NULL)
        return FR_FAIL;

    frlist_push(p_lst_header, p_st_node);
    *pp_session = NULL;

    return FR_FAIL;

}

FR_STATIC Http2_session * __http2_session_get(Frlist_header *p_lst_header, uint32_t u32_stream_id)
{
    Frlist_node *p_st_node = NULL;
    Http2_session *p_session = NULL;

    if(p_lst_header == NULL || u32_stream_id > 0x7fffffff)
        return NULL;


    p_st_node = FRLIST_FIRST_NODE(p_lst_header);
    while (p_st_node && p_st_node->data)
    {
        p_session = (Http2_session *)FRLIST_GET_NODE_DATA(p_st_node);
        if(p_session->u32_stream_id == u32_stream_id || p_session->u32_stream_id == 0x80000000)
//        if(p_session->u32_stream_id == u32_stream_id)
        {
            frlist_node_apart(p_lst_header, p_st_node);
            frfree(p_st_node);
            return p_session;
        }

        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    return NULL;

}

FR_STATIC int __http2_get_stream_id(char *p_data_in, unsigned int ui_data_len, uint32_t *p_u32_stream_id)
{
    uint32_t u32_stream_id = 0;

    if(p_data_in == NULL || ui_data_len < 9)
        return FR_FAIL;

    if(p_data_in[3] != 0x00 && p_data_in[3] != 0x01 && p_data_in[3] != 0x03)
        return FR_SUCC;

    p_data_in += 5;

    u32_stream_id = pntohi(p_data_in);
    u32_stream_id = u32_stream_id & 0x7fffffff;

    if(*p_u32_stream_id == 0x80000000)
        *p_u32_stream_id = u32_stream_id;

    return FR_SUCC;
}

FR_STATIC int __http_req_analysis(Apm_packet *p_st_packet, L7_session *p_st_session, Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    int i_ret = 0;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;
    L7session_http_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;
    char *p_tcp_body = p_st_packet->p_payload;
    unsigned int ui_tcp_body_len = p_st_packet->ui_payload_len;
    unsigned long ul_tmp = 0;

    p_st_private = (L7session_http_private*)p_st_session->p_session_private;

    if(p_st_private->i_version == 1)
    {
        if(p_st_private->p_http1_sess == NULL)
        {
            p_st_private->p_http1_sess = http1_session_create();
            if(p_st_private->p_http1_sess == NULL)
            {
                http_session_destroy((void *)(p_st_session->p_session_private));
                p_st_session->p_session_private = NULL;
                return APM_L7_ANALYZE_FAIL;
            }
        }

        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
        p_st_l4_trans = &p_comm_session->st_l4_trans;

        //如果数据包格式错误则
        if(p_http1_session->i_flag_abandon == 1)
        {
            //如果下一个req包数据进入 则销毁私有数据  否则直接返回 APM_L7_ANALYZE_TODO
            if(p_http1_session->i_flag_req_finish == 0)
            {
                if(http_session_reset(&p_st_session->p_session_private) == FR_FAIL)
                    goto ERROR;

                p_st_private = (L7session_http_private*)p_st_session->p_session_private;
                p_http1_session = p_st_private->p_http1_sess;
                p_comm_session = p_http1_session->p_st_comm_session;
                p_st_l4_trans = &p_comm_session->st_l4_trans;
            }
            else
            {
                return APM_L7_ANALYZE_TODO;
            }
        }

        //如果连续两个request数据则销毁上一次生成的私有数据
        if(p_comm_session->p_lst_comm_tmp)
        {
            if(http_session_reset(&p_st_session->p_session_private) == FR_FAIL)
                goto ERROR;

            p_st_private = (L7session_http_private*)p_st_session->p_session_private;
            p_http1_session = p_st_private->p_http1_sess;
            p_comm_session = p_http1_session->p_st_comm_session;
            p_st_l4_trans = &p_comm_session->st_l4_trans;
        }
    }
    else
    {
        //http2 session 处理
        if(p_st_private->p_http2_sess == NULL)
        {
            p_st_private->p_http2_sess = http2_session_create();
            if(p_st_private->p_http2_sess == NULL)
            {
                http_session_destroy(p_st_session->p_session_private);
                p_st_session->p_session_private = NULL;
                return APM_L7_ANALYZE_FAIL;
            }
        }
        else
        {
            //response 数据没结束
            if(p_st_private->u32_current_resp_id != 0x80000000)
            {
                //存储该 stream id 的私有数据存储
                __http2_session_add(&p_st_private->st_http2_session, &p_st_private->p_http2_sess);

                p_st_private->p_http2_sess = http2_session_create();
                if(p_st_private->p_http2_sess == NULL)
                {
                    http_session_destroy(p_st_session->p_session_private);
                    p_st_session->p_session_private = NULL;
                    return APM_L7_ANALYZE_FAIL;
                }
            }
        }

        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
        p_st_l4_trans = &p_comm_session->st_l4_trans;
    }

    //首包时间
    if(p_st_l4_trans->st_request_time_first_byte.tv_sec == 0 &&
       p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
    {
        //第一个包  st_request_time_first_byte
        if(p_comm_session->p_st_body_data_req == NULL)
        {
            p_comm_session->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
            if(p_comm_session->p_st_body_data_req == NULL)
                goto ERROR;

            i_ret = frreport_body_l7_add_connInfo(p_comm_session->p_st_body_data_req, p_st_conn);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }

        p_comm_session->ul_seq = frct_seq_increase(p_st_conn);

        if(frreport_body_l7_add_ulong(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_comm_session->ul_seq) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_int(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
            goto ERROR;

        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

    }
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
//        /* 请求的字节数 */
    p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

    switch (p_st_private->i_version)
    {
        case 0:
            i_ret = http_get_whole_req_inf(p_st_private, p_comm_session->p_st_body_data_req, p_tcp_body, ui_tcp_body_len);
            if(i_ret != APM_L7_ANALYZE_FAIL)
            {
                p_st_private->i_version = 1;
                break;
            }

            p_st_private->i_frame_type = 1;
            i_ret = nghttp2_analysis(p_tcp_body, ui_tcp_body_len, p_st_private, p_comm_session->p_st_body_data_req, FR_YES);
            if(i_ret != APM_L7_ANALYZE_FAIL)
            {
                p_st_private->i_version = 2;
            }

            if(i_ret == APM_L7_ANALYZE_SUCC && p_st_private->i_flag_report == 0)
            {
                http2_session_destroy(&p_st_private->p_http2_sess);
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }

            break;

        case 1:
            i_ret = http_get_whole_req_inf(p_st_private, p_comm_session->p_st_body_data_req, p_tcp_body, ui_tcp_body_len);
            break;

        case 2:
            p_st_private->i_frame_type = 1;
            i_ret = nghttp2_analysis(p_tcp_body, ui_tcp_body_len, p_st_private, p_comm_session->p_st_body_data_req, FR_YES);
            if(i_ret == APM_L7_ANALYZE_SUCC && p_st_private->i_flag_report == 0)
            {
                http2_session_destroy(&p_st_private->p_http2_sess);
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }
            break;

        default:
            goto ERROR;

    }

    if(i_ret == APM_L7_ANALYZE_SUCC)
    {
        bytebuff_free(&p_comm_session->p_st_data);
        p_comm_session->arr_charset[0] = '\0';
        if(p_st_private->i_version == 1)
        {
            p_http1_session->i_flag_req_finish = 0;
            if(p_comm_session->i_upgrade)
            {
                return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
            }
        }

        //request_time_us
        ul_tmp = (unsigned long)frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &p_st_packet->st_timestamp);
        if(frreport_body_l7_add_ulong(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;

        //响应字节数
        if(frreport_body_l7_add_long(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        //session 数据处理
        if(p_st_private->p_user_name)
        {
            i_ret = http_session_report(p_comm_session->p_st_body_data_req, p_st_private);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }

        //数据上报
        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        if(p_st_report_data == NULL)
            goto ERROR;

        //保存req数据
        p_comm_session->p_lst_req_tmp = FRREPORT_BODY_L7LIST_CLONE_REQ(p_comm_session->p_st_body_data_req);
        if(p_comm_session->p_lst_req_tmp == NULL)
            goto ERROR;

        //保存conn数据
        p_comm_session->p_lst_comm_tmp = FRREPORT_BODY_L7LIST_CLONE_COMM(p_comm_session->p_st_body_data_req);
        if(p_comm_session->p_lst_comm_tmp == NULL)
            goto ERROR;

        if(frreport_data_add_body(p_st_report_data, p_comm_session->p_st_body_data_req) == FR_FAIL)
            goto ERROR;
        p_comm_session->p_st_body_data_req = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;
        p_st_report_data = NULL;

        //req数据上报结束
        p_comm_session->i_flag_multipart = 0;
        p_comm_session->i_flag_chunk = 0;
        p_comm_session->i_flag_need = 0;
        p_comm_session->i_data_len = 0;

        if(p_st_private->i_version == 1)
            p_http1_session->i_flag_req_report_end = 1;
//        else if(p_st_private->p_http2_sess->u32_stream_id == 0x80000000)
//            http2_session_destroy(&p_st_private->p_http2_sess);
        else
            __http2_session_add(&p_st_private->st_http2_session, &p_st_private->p_http2_sess);

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }

    if(i_ret == APM_L7_ANALYZE_FAIL)
        goto ERROR;

    return i_ret;

ERROR:

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_session->p_session_private)
    {
        http_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
    }
    return APM_L7_ANALYZE_FAIL;
}


FR_STATIC int __http_resp_analysis(Apm_packet *p_st_packet, L7_session *p_st_session, Conntrack *p_st_conn, Frhash_header *p_st_hash_report)
{
    int i_ret = 0;
    Http1_session *p_http1_session = NULL;
    Http2_session *p_http2_session = NULL;
    Http_comm_session *p_comm_session = NULL;
    L7session_http_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;
    char *p_tcp_body = p_st_packet->p_payload;
    unsigned int ui_tcp_body_len = p_st_packet->ui_payload_len;
    unsigned long ul_tmp = 0;
    int i_resp_code = 0;

    p_st_private = (L7session_http_private*)p_st_session->p_session_private;

    if(p_st_private->i_version == 1)
    {
        //私有数据获取
        p_st_private = (L7session_http_private*)p_st_session->p_session_private;
        if(p_st_private->p_http1_sess == NULL)
            return APM_L7_ANALYZE_FAIL;

        p_http1_session = p_st_private->p_http1_sess;
        p_comm_session = p_http1_session->p_st_comm_session;
        p_st_l4_trans = &p_comm_session->st_l4_trans;

        //如果数据包错误直接返回 APM_L7_ANALYZE_TODO 并且i_flag_req_finish = 0
        if(p_http1_session->i_flag_abandon == 1)
        {
            p_http1_session->i_flag_req_finish = 0;
            return APM_L7_ANALYZE_TODO;
        }
    }
    else
    {
        //http2 session 处理
        if(__http2_get_stream_id(p_tcp_body, ui_tcp_body_len, &p_st_private->u32_current_resp_id) == FR_FAIL)
        {
            http_session_destroy(p_st_session->p_session_private);
            p_st_session->p_session_private = NULL;
            return APM_L7_ANALYZE_FAIL;
        }

        if(p_st_private->p_http2_sess == NULL)
        {
            p_st_private->p_http2_sess = __http2_session_get(&p_st_private->st_http2_session, p_st_private->u32_current_resp_id);
            if(p_st_private->p_http2_sess == NULL)
            {
                p_st_private->p_http2_sess = http2_session_create();
                if(p_st_private->p_http2_sess == NULL)
                {
                    http_session_destroy(p_st_session->p_session_private);
                    p_st_session->p_session_private = NULL;
                    return APM_L7_ANALYZE_FAIL;
                }
            }
        }

        p_http2_session = p_st_private->p_http2_sess;
        p_comm_session = p_http2_session->p_st_comm_session;
        p_st_l4_trans = &p_comm_session->st_l4_trans;
    }

    //首包时间
    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 &&
        p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        //todo HTTP 短连接 request 信息处理
        if(p_comm_session->p_st_body_data_req)
        {
            i_ret = http1_get_resp_code(p_tcp_body, ui_tcp_body_len, &i_resp_code);
            if(i_ret == FR_SUCC)
            {
                if(i_resp_code == 100)
                    return APM_L7_ANALYZE_TODO;
            }
            
            i_ret = http_req_report(p_st_private, p_st_hash_report);
            if(i_ret == APM_L7_ANALYZE_FAIL)
                goto ERROR;
            
            bytebuff_free(&p_comm_session->p_st_data);
        }
        
        
        //应答发起时间戳
        p_comm_session->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if(p_comm_session->p_st_body_data_resp == NULL)
            goto ERROR;

        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        if(p_comm_session->ul_seq == 0)
        {
            p_comm_session->ul_seq = frct_seq_increase(p_st_conn);
            if(frreport_body_l7_add_ulong(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_REQ_ID, p_comm_session->ul_seq) == FR_FAIL)
                goto ERROR;
        }

        if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

    }

    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
    //响应的字节数
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

    switch (p_st_private->i_version)
    {
        case 0:
            i_ret = http_get_whole_resp_inf(p_st_private, p_comm_session->p_st_body_data_resp, p_tcp_body, ui_tcp_body_len);
            if(i_ret != APM_L7_ANALYZE_FAIL)
            {
                p_st_private->i_version = 1;
                break;
            }

            p_st_private->i_frame_type = 2;
            i_ret = nghttp2_analysis(p_tcp_body, ui_tcp_body_len, p_st_private, p_comm_session->p_st_body_data_resp, FR_YES);
            if(i_ret != APM_L7_ANALYZE_FAIL)
            {
                p_st_private->i_version = 2;
            }

            if(i_ret == APM_L7_ANALYZE_SUCC && p_st_private->i_flag_report == 0)
            {
                http2_session_destroy(&p_st_private->p_http2_sess);
                p_st_private->u32_current_resp_id = 0x80000000;
                return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }

            break;

        case 1:
            i_ret = http_get_whole_resp_inf(p_st_private, p_comm_session->p_st_body_data_resp, p_tcp_body, ui_tcp_body_len);
            break;

        case 2:
            p_st_private->i_frame_type = 2;
            i_ret = nghttp2_analysis(p_tcp_body, ui_tcp_body_len, p_st_private, p_comm_session->p_st_body_data_resp, FR_YES);
            if(i_ret == APM_L7_ANALYZE_SUCC && p_st_private->i_flag_report == 0)
            {
                http2_session_destroy(&p_st_private->p_http2_sess);
                p_st_private->u32_current_resp_id = 0x80000000;
                return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }

            break;

        default:
            goto ERROR;
    }

    //只有在存在 req 的情况下才上报
    if(i_ret == APM_L7_ANALYZE_SUCC)
    {
        if(p_st_private->i_version == 1)
            p_http1_session->i_flag_resp_finish = 0;

        if(p_comm_session->i_upgrade)
        {
            if(p_comm_session->l_response_code == 101)
                p_st_private->i_version = 2;

            if(http_session_reset(&p_st_session->p_session_private) == FR_FAIL)
            {
                http_session_destroy(p_st_session->p_session_private);
                p_st_session->p_session_private = NULL;
            }
            return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
        }

        //comm信息
        if(p_st_l4_trans->st_request_time_first_byte.tv_sec)
        {
            //comm
            if(FRREPORT_BODY_L7LIST_SET_COMM(p_comm_session->p_st_body_data_resp, &p_comm_session->p_lst_comm_tmp) == FR_FAIL)
                goto ERROR;

            //把req数据链表添加到resp中
            if(FRREPORT_BODY_L7LIST_SET_REQ(p_comm_session->p_st_body_data_resp, &p_comm_session->p_lst_req_tmp) == FR_FAIL)
                goto ERROR;

            //server_time_us
            ul_tmp = (unsigned long)frtime_diff(&p_st_l4_trans->st_request_time, &p_st_l4_trans->st_response_time_first_byte);
            if(frreport_body_l7_add_ulong(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
                goto ERROR;
        }
        else
        {
            i_ret = frreport_body_l7_add_connInfo(p_comm_session->p_st_body_data_resp, p_st_conn);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }

        if(p_comm_session->ul_seq == 0)
            p_comm_session->ul_seq = frct_seq_increase(p_st_conn);

        if(frreport_body_l7_add_long(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
            goto ERROR;

        if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        ul_tmp = (unsigned long)frtime_diff(&p_st_l4_trans->st_response_time_first_byte, &p_st_l4_trans->st_response_time);
        if(frreport_body_l7_add_ulong(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;

        if(p_st_l4_trans->st_request_time_first_byte.tv_sec)
            p_st_l4_trans->ul_response_time_us = (unsigned long)frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_packet->st_timestamp));
        else
        {

            if(p_st_private->i_version == 2)
            {
                if(frreport_body_l7_add_long(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 0) == FR_FAIL)
                    goto ERROR;

                if(frreport_body_l7_add_str(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_TRANS_TITLE, p_http2_session->p_title) == FR_FAIL)
                    goto ERROR;
            }
            else
                goto ERROR;

            if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
                goto ERROR;

            if(frreport_body_l7_add_timeval(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
                goto ERROR;

//            if(http_session_reset(&p_st_session->p_session_private) == FR_FAIL)
//            {
//                http_session_destroy(p_st_session->p_session_private);
//                p_st_session->p_session_private = NULL;
//            }
//            p_st_private->u32_current_resp_id = 0x80000000;
//            return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
        }

        if(p_comm_session->p_err_msg)
        {
            //err message 上报
            i_ret = frreport_body_l7_add_str(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_ERR_MSG, p_comm_session->p_err_msg);
            if(i_ret == FR_FAIL)
                goto ERROR;

            //resp code 上报
            i_ret = frreport_body_l7_add_long(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE, 500);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }
        else
        {
            //resp code 上报
            i_ret = frreport_body_l7_add_long(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE, p_comm_session->l_response_code);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }

        //resp code string 上报
        i_ret = frreport_body_l7_add_str(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_CODE_STRING, p_comm_session->p_code_string);
        if(i_ret == FR_FAIL)
            goto ERROR;

        if(p_comm_session->p_err_msg == NULL)
        {
            i_ret = frreport_body_l7_add_str(p_comm_session->p_st_body_data_resp, APM_REPORT_KEY_RESP_ERR_MSG, p_comm_session->p_code_string);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }


        if(p_st_l4_trans->st_request_time_first_byte.tv_sec == 0)
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        else
            p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if(p_st_report_data == NULL)
            goto ERROR;

        //resp 数据上报
        if(frreport_data_add_body(p_st_report_data, p_comm_session->p_st_body_data_resp) == FR_FAIL)
            goto ERROR;
        p_comm_session->p_st_body_data_resp = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;

        p_st_report_data = NULL;

        if(http_session_reset(&p_st_session->p_session_private) == FR_FAIL)
        {
            http_session_destroy(p_st_session->p_session_private);
            p_st_session->p_session_private = NULL;
        }

        p_st_private->u32_current_resp_id = 0x80000000;
        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }

    if(i_ret == APM_L7_ANALYZE_FAIL)
        goto ERROR;

    return i_ret;

ERROR:

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_session->p_session_private)
    {
        http_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
    }
    return APM_L7_ANALYZE_FAIL;
}


/*******************************************************************************
*  FUNC     :  http的packet解析
*  ARGS     :  p_st_conn                (入力链接信息)
            :  p_st_packet             (入力packet信息)
            :  p_st_hash_report         (保存Frreport_data)
            :  p_st_list_output         (保存Analyz_data_out)
*  RTN      :  APM_L7_ANALYZE_SUCC      (成功)
*           ： APM_L7_ANALYZE_FAIL      (失败)
*           ： APM_L7_ANALYZE_TODO      (数据包未完整)
*  NOTE     :
*******************************************************************************/
int http_analysis(Conntrack *p_st_conn
        , Apm_packet *p_st_packet
        , Frhash_header *p_st_hash_report)
{

    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;                   /* L7session */
    L7session_http_private *p_st_private = NULL;       /* http的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
       || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;


    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //获取private
    if(p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = http_private_create();
        if(p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    p_st_private = (L7session_http_private*)p_st_session->p_session_private;

    //fin syn
    if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        http_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }
    else if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN)
    {
        if(p_st_private && p_st_private->i_version == 1)
        {
            if(p_st_private->p_http1_sess && p_st_private->p_http1_sess->p_st_comm_session
               &&p_st_private->p_http1_sess->p_st_comm_session->p_st_body_data_resp)
            {
                i_ret = http_resp_report(p_st_private, p_st_hash_report);
                if(i_ret == APM_L7_ANALYZE_FAIL)
                {
                    http_session_destroy((void *)(p_st_session->p_session_private));
                    p_st_session->p_session_private = NULL;
                    return APM_L7_ANALYZE_FAIL;
                }
            }
        }
        else
        {
            http_session_destroy((void *)(p_st_session->p_session_private));
            p_st_session->p_session_private = NULL;
            return APM_L7_ANALYZE_SUCC;
        }
    }
        

    if(p_st_private->i_version == 0)
    {
        //todo detect 版本
        if(http1_detect(p_st_conn, p_st_packet) == APM_L7_IS_YES)
            p_st_private->i_version = 1;
        else if(nghttp2_detect(p_st_conn, p_st_packet) == APM_L7_IS_YES)
            p_st_private->i_version = 2;
        else
            return APM_L7_ANALYZE_SUCC;
    }

    //request
    if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        i_ret = __http_req_analysis(p_st_packet, p_st_session, p_st_conn, p_st_hash_report);
        return i_ret;
    }
    else
    {
        i_ret = __http_resp_analysis(p_st_packet, p_st_session, p_st_conn, p_st_hash_report);
        return i_ret;
    }

}

FR_STATIC void __http2_session_node_free(Frlist_node *p_st_node)
{
    Http2_session *p_node_data = NULL;

    if(p_st_node && p_st_node->data)
    {
        p_node_data = (Http2_session *)FRLIST_GET_NODE_DATA(p_st_node);
        http2_session_destroy(&p_node_data);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(http的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int http_session_destroy(void *p_private_session)
{
    //todo
    L7session_http_private *p_st_private = (L7session_http_private *)p_private_session;

    if(p_st_private)
    {
        http2_session_destroy(&p_st_private->p_http2_sess);

        http1_session_destroy(&p_st_private->p_http1_sess);

        frlist_remove_all(&p_st_private->st_http2_session, __http2_session_node_free);

        if(p_st_private->p_inflater_ptr)
            nghttp2_hd_inflate_del(p_st_private->p_inflater_ptr);

        if(p_st_private->p_user_name)
            frfree(p_st_private->p_user_name);
        
        frfree(p_st_private);
    }
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是TCP协议
*  ARGS     :  p_st_conn                    输入数据信息
*           :  p_st_packet                 输入数据
*  RTN      :  APM_L7_IS_NO                 不属于TCP协议
*           :  APM_L7_IS_YES                属于TCP协议
*  NOTE     :
*******************************************************************************/
int http_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = 0;

    i_ret = http1_detect(p_st_conn, p_st_packet);
    if(i_ret == APM_L7_IS_YES)
        return APM_L7_IS_YES;

    i_ret = nghttp2_detect(p_st_conn, p_st_packet);
    if(i_ret == APM_L7_IS_YES)
        return APM_L7_IS_YES;

    return APM_L7_IS_NO;
}


